package de.fzi.kasma.learner.function.kernel.rdf;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Set;

import org.openrdf.model.vocabulary.RDF;

import com.sleepycat.je.DatabaseException;

import de.fzi.kasma.learner.path.PathEdge;
import de.fzi.kasma.learner.path.PathGraph;
import edu.unika.aifb.graphindex.data.Table;
import edu.unika.aifb.graphindex.index.DataIndex;
import edu.unika.aifb.graphindex.index.IndexDirectory;
import edu.unika.aifb.graphindex.index.IndexReader;
import edu.unika.aifb.graphindex.storage.StorageException;

public class RDFKernel {
	private DataIndex m_idx;
	private KernelCache cache;

	private static final String KEY_DELIM = Character.toString((char) 31);

	public RDFKernel(DataIndex idx) {
		this.m_idx = idx;
	}

	public void calculateKernel(PathGraph pg, String cacheDir) throws Exception {
		GraphMap gm = new GraphMap(new File(cacheDir));
		createGM(pg, gm);

		initializePartitions(gm);

	}

	private void initializePartitions(GraphMap gm) throws Exception {

		// TODO Auto-generated method stub

		Partition pn = new Partition(cache);
		Color nodeColor = pn.addColor("");
		Set<Integer> nodes = gm.getNodes();
		for (Integer node : nodes) {
			nodeColor.add(node);
		}

		Partition pe = new Partition(cache);
		Set<Integer> edges = gm.getEdges();
		for (Integer edge : edges) {
			Integer es = gm.getEdgeSubjIds(edge);
			Integer et = gm.getEdgeObjIds(edge);
			Color edgeColor = pe.addColor(es + KEY_DELIM + edge + KEY_DELIM
					+ et);
			edgeColor.add(edge);
		}

	}

	/**
	 * This function creates a starting graph map for calculateKernel().
	 * 
	 * @param pg
	 *            This is a PathGraph
	 * @param gm
	 *            This is a GraphMap
	 * @throws StorageException
	 */
	private void createGM(PathGraph pg, GraphMap gm) throws StorageException {
		// Iterate all edges in PathGraph.
		for (PathEdge edge : pg.edgeSet()) {
			// Starting values for source and target are null.
			String source = null;
			String target = null;
			// If the source or target is an entity it takes the label of
			// source, or target.
			if (edge.getSource().isEntity())
				source = edge.getSource().getLabel();
			if (edge.getTarget().isEntity())
				target = edge.getTarget().getLabel();

			// Iterate through all triples .
			for (Iterator<String[]> ti = m_idx.iterator(source,
					edge.getProperty(), target); ti.hasNext();) {

				// String[] triple = [Source,Predicate,Target]
				String[] triple = ti.next();
				String subj = triple[0];
				String pred = triple[1];
				String obj = triple[2];

				// subjId = id of the subject node, targetId = id of the target
				// node.
				Integer subjId = gm.getNodeId(subj);
				Integer targetId = gm.getNodeId(obj);

				// If subjId is null , then add the id of the subject into
				// database.
				if (subjId == null) {
					subjId = gm.addNode(subj);
				}
				if (edge.getProperty().equals(RDF.TYPE.toString())) {
					// TODO When schema level information needed, store it in DB
					// here...
					continue;
				}

				// If targetId is null,then add the id of the object into the
				// database.
				if (targetId == null) {
					targetId = gm.addNode(obj);
				}

				// Build a new string from the concatenation of the
				// source,predicate and target.
				String indexEdge = new StringBuilder().append(subj)
						.append(KEY_DELIM).append(pred).append(KEY_DELIM)
						.append(obj).toString();

				// If edgeId is null, then add the id of the indexEdge into the
				// database.
				Integer edgeId = gm.getEdgeId(indexEdge);
				if (edgeId == null) {
					edgeId = gm.addEdge(indexEdge);
				}

				// Adds the edge id of the subject into the database.
				gm.addSubjId2EdgeId(subjId, edgeId);
				Set<Integer> edgeIds = gm.getSubjEdgeIds(gm.getNodeId(subj));

				// Adds the object id of the edge into the database.
				gm.addEdgeId2ObjId(edgeId, targetId);
				Integer objIds = gm.getEdgeObjIds(gm.getEdgeId(indexEdge));

				// Adds the source id of the edge into the database.
				gm.addEdgeId2SubjId(edgeId, subjId);

			}
		}
	}

	public Set<String> getTypes(String uri) throws StorageException {
		Table<String> table = m_idx.getTriples(uri, RDF.TYPE.stringValue(),
				null);
		Set<String> types = table.getUniqueValueSet(table.getColumnName(2));
		return types;
	}

	public static void main(String[] args) throws Exception {
		IndexReader ir = new IndexReader(new IndexDirectory("C:\\Sindex"));
		RDFKernel kern = new RDFKernel(ir.getDataIndex());
		PathGraph q = new PathGraph();
		q.addEdge("?u", "http://www.movie.org/ontology.owl#like", "?m");
		q.addEdge("?u", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
				"http://www.movie.org/ontology.owl#User");
		q.addEdge("?m", "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
				"http://www.movie.org/ontology.owl#Movie");
		kern.calculateKernel(q, "C:\\Sindex");
	}
}
